/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.npmpackage.core.npminstall.global;

import com.inspur.edp.web.common.entity.NodeJsCommandEnum;
import com.inspur.edp.web.common.environment.ExecuteEnvironment;
import com.inspur.edp.web.common.io.FileUtility;
import com.inspur.edp.web.common.io.NodejsFunctionUtility;
import com.inspur.edp.web.common.logger.WebLogger;
import com.inspur.edp.web.common.utility.*;
import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter;
import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse;

import java.io.File;

/**
 * @author guozhiqi
 */
public class GlobalNpmInstallCommandExecutor {
    /**
     * 命令执行
     *
     * @param npmInstallParameter
     * @param npmName
     */
    public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String npmName, String version) {
        if (StringUtility.isNullOrEmpty(npmName)) {
            return NpmPackageResponse.create();
        }
        if (StringUtility.isNullOrEmpty(version)) {
            version = "latest";
        }
        // 构造install 命令参数 执行npm包安装操作

        WebLogger.Instance.info("执行全局离线包安装:" + npmName + "@" + version, GlobalNpmInstallCommandExecutor.class.getName());
        boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment() == ExecuteEnvironment.UpgradeTool;
        String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool);

        String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentWorkPath);
        String npmInstallCommandExecuteWithPath = "npm install " + npmName + "@" + version + " ";

        String npmInstallCommand = GlobalNpmInstallCommandParameterGenerator.generate(npmInstallParameter);


        String[] command = new String[2];
        // 盘符独立打开
        command[0] = npmInstallCommandExecuteWithPath + npmInstallCommand;
        command[1] = "exit";
        // 执行npm 包安装
        return runCommand(command, true);
    }

    private static NpmPackageResponse runCommand(String[] commands, boolean isWait) {
        String command = String.join(" && ", commands);
        return runCommand(command, isWait);
    }

    /**
     * 执行命令
     *
     * @param command 待执行命令
     * @param isWait  是否等待返回结果
     */
    private static NpmPackageResponse runCommand(String command, boolean isWait) {
        StringBuffer errorSB = new StringBuffer();
        String errorMessage = CommandLineUtility.executeCommand(command, errorSB);
        // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出
        if (!StringUtility.isNullOrEmpty(errorMessage)) {
            return NpmPackageResponse.createError("npm install failed, the reason is " + errorMessage);
        }

        // 如果存在输出异常 那么不再继续执行
        if (!StringUtility.isNullOrEmpty(errorSB.toString()) && errorSB.toString().toLowerCase().contains("npm err")) {
            // 如果是特殊的错误  表示在windows上依赖包版本不对，导致无法正确安装问题
            // 先将
            if (OperatingSystemUtility.isWindows() && errorSB.toString().toLowerCase().contains("npm ERR! Maximum call stack size exceeded".toLowerCase())) {
                // 仅在windows下执行
                String globalNpmPath = GlobalNpmDeployPathGenerator.getGlobalNpmPath();
                if (!StringUtility.isNullOrEmpty(globalNpmPath)) {
                    File globalNpmPathFile = new File(globalNpmPath);
                    if (globalNpmPathFile.exists()) {
                        // 获取对应的jit 路径
                        String globalJitPath = FileUtility.combine(globalNpmPath, "node_modules", "@farris");
                        File globalJitPathFile = new File(globalJitPath);
                        if (globalJitPathFile.exists() && globalJitPathFile.isDirectory()) {
                            // 重命名文件目录
                            String globalJitRenamedPath = FileUtility.combine(globalNpmPath, "node_modules", "@farris-autobackup");
                            // 将源目录进行重命名
                            FileUtility.reName(globalJitPath, globalJitRenamedPath);
                            FileUtility.deleteFolder(globalJitPath);
                        }
                        WebLogger.Instance.info("npm在线安装全局离线包出现版本依赖错误，系统自动修复，重新进行安装处理！", GlobalNpmInstallCommandExecutor.class.getName());
                        return runCommand(command, isWait);
                    }
                }
            }
            return NpmPackageResponse.createError(errorSB.toString());
        }

        return NpmPackageResponse.create();
    }


}
